/* !
 * elasticlunr.EventEmitter
 * Copyright (C) @YEAR Oliver Nightingale
 * Copyright (C) @YEAR Wei Song
 */

export default function (elasticlunr) {
  /**
   * elasticlunr.EventEmitter is an event emitter for elasticlunr.
   * It manages adding and removing event handlers and triggering events and their handlers.
   *
   * Each event could has multiple corresponding functions,
   * these functions will be called as the sequence that they are added into the event.
   *
   * @constructor
   */
  elasticlunr.EventEmitter = function () {
    this.events = {};
  };

  /**
   * Binds a handler function to a specific event(s).
   *
   * Can bind a single function to many different events in one call.
   *
   * @param {String} [eventName] The name(s) of events to bind this function to.
   * @param {Function} fn The function to call when an event is fired.
   * @memberOf EventEmitter
   */
  elasticlunr.EventEmitter.prototype.addListener = function () {
    var args = Array.prototype.slice.call(arguments),
      fn = args.pop(),
      names = args;

    if (typeof fn !== 'function') throw new TypeError('last argument must be a function');

    names.forEach(function (name) {
      if (!this.hasHandler(name)) this.events[name] = [];
      this.events[name].push(fn);
    }, this);

    return true;
  };

  /**
   * Removes a handler function from a specific event.
   *
   * @param {String} eventName The name of the event to remove this function from.
   * @param {Function} fn The function to remove from an event.
   * @memberOf EventEmitter
   */
  elasticlunr.EventEmitter.prototype.removeListener = function (name, fn) {
    var fnIndex;

    if (!this.hasHandler(name)) return;

    fnIndex = this.events[name].indexOf(fn);

    if (fnIndex === -1) return;

    this.events[name].splice(fnIndex, 1);

    if (this.events[name].length === 0) delete this.events[name];
  };

  /**
   * Call all functions that bounded to the given event.
   *
   * Additional data can be passed to the event handler as arguments to `emit`
   * after the event name.
   *
   * @param {String} eventName The name of the event to emit.
   * @memberOf EventEmitter
   */
  elasticlunr.EventEmitter.prototype.emit = function (name) {
    var args;

    if (!this.hasHandler(name)) return;

    args = Array.prototype.slice.call(arguments, 1);

    this.events[name].forEach(function (fn) {
      fn.apply(undefined, args);
    }, this);
  };

  /**
   * Checks whether a handler has ever been stored against an event.
   *
   * @param {String} eventName The name of the event to check.
   * @private
   * @memberOf EventEmitter
   */
  elasticlunr.EventEmitter.prototype.hasHandler = function (name) {
    return name in this.events;
  };
};
